#include "Cylinder.h"

using Magick::Image;
using Magick::InitializeMagick;
namespace shapes{

	GLuint Cylinder::textureObjects[1];

Cylinder::Cylinder() 
: quadric(0), alignAngle(0.0f), radius(1.0f), height(5.0f), closed( true ), textured(false)
{
	slices  = 32;
	stacks  = 32;
	axis[0] = 0.0f; 
	axis[1] = 0.0f; 
	axis[2] = 1.0f; 
}

Cylinder::Cylinder(Cylinder& cylinder) 
: alignAngle(cylinder.alignAngle), quadric(0), closed( cylinder.closed ), textured( cylinder.textured )
{
	slices = cylinder.slices;
	stacks = cylinder.stacks;
	for ( int col=0; col<3; col++ ) {
		axis[col] = cylinder.axis[col];
	}
}

Cylinder::Cylinder(float setRadius, float setHeight, int RGBAvalues) : quadric(0), alignAngle(0.0f), closed(true), textured(false)
{
	slices = 32;
	stacks = 32;

	radius = setRadius;
	height = setHeight;

	setColor(RGBAvalues);
}

Cylinder::~Cylinder() {
  if ( quadric != 0 ) {
    gluDeleteQuadric( quadric );
  }
}

Cylinder& Cylinder::operator=(Cylinder& cylinder) 
{
  slices = cylinder.slices;
  stacks = cylinder.stacks; 
  alignAngle = cylinder.alignAngle;
  // no need to change d_quadric
  for ( int col=0; col<3; col++ ) {
    axis[col] = cylinder.axis[col];
  }
  return *this;
}

void Cylinder::setMajorAxis( Vector3D _axis ) {
	float length = _axis.X * _axis.X + _axis.Y * _axis.Y + _axis.Z * _axis.Z;
	length = sqrt( length );
	axis[0] = _axis.X/length;
	axis[1] = _axis.Y/length;
	axis[2] = _axis.Z/length;

	alignAngle = acos( axis[2] )/3.141593 * 180.0;
}

void Cylinder::draw() 
{
	ShapeNode::draw();
	glPushMatrix();

	// Rotate the cylinder as required
	glRotatef( alignAngle, -axis[1], axis[0], 0.0f );
	
	// Move the cylinder to the origin
	glTranslatef( 0.0f, 0.0f, -height/2.0f );
	if ( quadric == 0 ) 
	{
		quadric = gluNewQuadric();
	}

	//apply rgb color
	glColor3f(r, g, b);
	gluCylinder( quadric, radius, radius, height, slices, stacks );

	if ( closed && !textured) 
	{
		//The bottom Disk
		glTranslatef( 0.0f, 0.0f, 0.0f );
		gluDisk( quadric, 0.0, radius, slices, stacks );

		//The top Disk
		glTranslatef( 0.0f, 0.0f, height );
		gluDisk( quadric, 0.0, radius, slices, stacks );
	} 
	else if (closed && textured) 
	{
		//Apply textures to the top and bottom disks
		glEnable(GL_TEXTURE_2D);
		glBindTexture(GL_TEXTURE_2D, textureObjects[currentTexture]);
		gluQuadricTexture(quadric, GL_TRUE);
		//The bottom Disk
		glTranslatef( 0.0f, 0.0f, 0.0f );
		gluDisk( quadric, 0.0, radius, slices, stacks );
		glTranslatef( 0.0f, 0.0f, height );
		gluDisk( quadric, 0.0, radius, slices, stacks );
		glDisable(GL_TEXTURE_2D);
	}
	glPopMatrix();
	ShapeNode::drawFinish();
}

//Texture Loader for the cylinder--
//Inspired by jlang from textureMapping tutorial.
void Cylinder::setTexture(char *fileName)
{
	//we will just set our variables each time we call this function... kinda gross but it will
	//do for now.
	textureCount = 1;
	currentTexture = 0;
	if(glIsTexture(textureObjects[currentTexture])){
		//texture is already loaded, let's get out of here
		return;
	}

	glGenTextures(1, &textureObjects[0]);
	
	glPixelStorei(GL_UNPACK_ALIGNMENT, textureObjects[currentTexture]);
	//Bind texture
	glBindTexture( GL_TEXTURE_2D, textureObjects[currentTexture]);

	//Load the Image from disk
	Image image;
	image.read( fileName );
	//yep-- no error handling
	
	//setting up the texture environment
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.columns(), image.rows(), 0,
				GL_BGRA_EXT,
				GL_UNSIGNED_SHORT, //16 bits per channel-- if ImageMagick was compiled as Q16
				image.getPixels(0, 0, image.columns(), image.rows()));

	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
}